<html>
<head>
  <style>
  @font-face {
    font-family: mipro;
    src: url('./mipro.ttf'); 
  }
  p {
    font-family: mipro;
    position: absolute;
    left: 610px;
    top: 10px;
  }
  </style>
</head>
<body>
	<canvas width="600" height="600" id="main_canv" onmousemove="cnvs_getCoordinates(event)" onmouseout="cnvs_clearCoordinates()"></canvas>
    <p id="xycoordinates"></p>
</body>

<script>
    function partial(func, ...argsBound) {
        return function(...args) {
            return func.call(this, ...argsBound, ...args);
        }
    }
    
	var canvas = document.getElementById("main_canv");
	var context = canvas.getContext("2d");
    
	var dwar = {}
    mainThis = {};
	mainThis.allPoint = [];
    mainThis.allFunctionPoint = [];
    
	function _init_coordinatemap(context,mainThis,oXY,size) {
		oX = oXY[0]
		oY = oXY[1]
		
		mainThis.x = oX;
		mainThis.y = oY;
		mainThis.width = size/2;
		mainThis.domain = [-mainThis.width,mainThis.width]
        mainThis.range = [-mainThis.width,mainThis.width]
        
		context.beginPath();
		context.moveTo(oX,oY-7);
		context.lineTo(oX,oY+7);
		context.moveTo(oX-7,oY);
		context.lineTo(oX+7,oY);
	    context.closePath();
        
        context.strokeStyle = "#000";
		context.lineWidth = 1;
        context.stroke();
        
        context.font = "17px mipro"
        context.textAlign = 'left';
        context.fillStyle = "#000"
		console.log("Init_coordinatemap...OK")
	}
    dwar.init_coordinatemap = partial(_init_coordinatemap,context,mainThis)
    
	function _setScope(context,mainThis,domain,range) {
        mainThis.domain = domain;
        mainThis.range = range;
    }
    dwar.setScope = partial(_setScope,context,mainThis)
    
    function _setBackground(context,mainThis,flag) {
        mainThis.backgroundFlag = flag
    }
    dwar.setBackground = partial(_setBackground,context,mainThis)
    
    function _setGraduation(context,mainThis,flag) {
        mainThis.graduationFlag = flag
    }
    dwar.setGraduation = partial(_setGraduation,context,mainThis)
    
	function _addPositiveXaxis(context,mainThis) {
		context.beginPath();
		context.moveTo(oX,oY);
		context.lineTo(oX+mainThis.width,oY);
        
        if (mainThis.graduationFlag) {
            for (i=0;i<mainThis.width/10;i++) {
                context.moveTo(mainThis.x+i*10,mainThis.y-2)
                context.lineTo(mainThis.x+i*10,mainThis.y+1)
            }
        }
        context.closePath();
        context.stroke();
        
        if (mainThis.backgroundFlag) {
            for (i=0;i<mainThis.width/10;i++) {
                context.moveTo(mainThis.x+i*10,mainThis.y-mainThis.width)
                context.lineTo(mainThis.x+i*10,mainThis.y+mainThis.width)
            }
            
            oldstyle = context.strokeStyle
            context.strokeStyle = mainThis.backgroundFlag
            context.stroke();
            context.strokeStyle = oldstyle
        }
	}
	dwar.addPositiveXaxis = partial(_addPositiveXaxis,context,mainThis)
    
	function _addNegativeXaxis(context,mainThis) {
		context.beginPath();
		context.moveTo(oX,oY);
		context.lineTo(oX-mainThis.width,oY);
        
		if (mainThis.graduationFlag) {
            for (i=0;i<mainThis.width/10;i++) {
                context.moveTo(mainThis.x-i*10,mainThis.y-2)
                context.lineTo(mainThis.x-i*10,mainThis.y+1)
            }
        }
		context.closePath();
        context.stroke();
        
        
		if (mainThis.backgroundFlag) {
            for (i=0;i<mainThis.width/10;i++) {
                context.moveTo(mainThis.x-i*10,mainThis.y-mainThis.width)
                context.lineTo(mainThis.x-i*10,mainThis.y+mainThis.width)
            }
            
            oldstyle = context.strokeStyle
            context.strokeStyle = mainThis.backgroundFlag
            context.stroke();
            context.strokeStyle = oldstyle
        }
	}
	dwar.addNegativeXaxis = partial(_addNegativeXaxis,context,mainThis)
   
	function _addPositiveYaxis(context,mainThis) {
		context.beginPath();
		context.moveTo(oX,oY);
		context.lineTo(oX,oY+mainThis.width);
		
		if (mainThis.graduationFlag) {
            for (i=0;i<mainThis.width/10;i++) {
                context.moveTo(mainThis.x+2,mainThis.y-i*10)
                context.lineTo(mainThis.x-1,mainThis.y-i*10)
            }
        }
		context.closePath();
        context.stroke();
        
        
		if (mainThis.backgroundFlag) {
            for (i=0;i<mainThis.width/10;i++) {
                context.moveTo(mainThis.x+mainThis.width,mainThis.y-i*10)
                context.lineTo(mainThis.x-mainThis.width,mainThis.y-i*10)
            }
            
            oldstyle = context.strokeStyle
            context.strokeStyle = mainThis.backgroundFlag
            context.stroke();
            context.strokeStyle = oldstyle
        }
	}
    dwar.addPositiveYaxis = partial(_addPositiveYaxis,context,mainThis)
    
	function _addNegativeYaxis(context,mainThis) {
		context.beginPath();
		context.moveTo(oX,oY);
		context.lineTo(oX,oY-mainThis.width);
		
        if (mainThis.graduationFlag) {
            for (i=0;i<mainThis.width/10;i++) {
                context.moveTo(mainThis.x+2,mainThis.y+i*10)
                context.lineTo(mainThis.x-1,mainThis.y+i*10)
            }
        }
		context.closePath();
        context.stroke();
        
        if (mainThis.backgroundFlag) {
            for (i=0;i<mainThis.width/10;i++) {
                context.moveTo(mainThis.x+mainThis.width,mainThis.y+i*10)
                context.lineTo(mainThis.x-mainThis.width,mainThis.y+i*10)
            }
            oldstyle = context.strokeStyle
            context.strokeStyle = mainThis.backgroundFlag
            context.stroke();
            context.strokeStyle = oldstyle
        }
	}
    dwar.addNegativeYaxis = partial(_addNegativeYaxis,context,mainThis)
    
	function _setColor(context,mainThis,color) {
		context.strokeStyle = color;
	}
    dwar.setColor = partial(_setColor,context,mainThis)
	
    function __addPoint(context,mainThis,pointXY) {
        if (pointXY[0] > mainThis.width) { x = 0;y = 0 }
		else if (pointXY[0] < -mainThis.width) { x = 0;y = 0 }
		else { x = pointXY[0] };
        
        if (pointXY[1] > mainThis.width) { x = 0;y = 0 }
		else if (pointXY[1] < -mainThis.width) { x = 0;y = 0 }
        else { y = pointXY[1] };
        
        // console.log(x,y)
        x = x + mainThis.x;
        y = -y + mainThis.y;
        
            context.beginPath();
            context.moveTo(x-1,y);
            context.lineTo(x+1,y);
            context.moveTo(x,y-1);
            context.lineTo(x,y+1);
            context.closePath();
            context.stroke();
            
		mainThis.allPoint[mainThis.allPoint.length] = [x,y];
	}
    dwar._addPoint = partial(__addPoint,context,mainThis)
    
    function _addPoint(context,mainThis,pointXY,flag) {
        // console.log([pointXY[0]*mainThis.width/mainThis.domain,pointXY[1]*mainThis.width/mainThis.domain])
        __addPoint(context,mainThis,[pointXY[0]*mainThis.width/mainThis.domain,pointXY[1]*mainThis.width/mainThis.range],flag)
    }
    dwar.addPoint = partial(_addPoint,context,mainThis)
    
    function __addFunctionPoint(context,mainThis,pointXY) {
        if (pointXY[0] > mainThis.width) { x = 0;y = 0 }
		else if (pointXY[0] < -mainThis.width) { x = 0;y = 0 }
		else { x = pointXY[0] };
        
        if (pointXY[1] > mainThis.width) { x = 0;y = 0 }
		else if (pointXY[1] < -mainThis.width) { x = 0;y = 0 }
        else { y = pointXY[1] };
        
        // console.log(x,y)
        x = x + mainThis.x;
        y = -y + mainThis.y;
        
            context.beginPath();
            context.lineTo(x,y);
            context.closePath();
            context.stroke();

		mainThis.allFunctionPoint[mainThis.allFunctionPoint.length] = [x,y];
	}
    dwar._addFunctionPoint = partial(__addFunctionPoint,context,mainThis)
    
    function _addFunctionPoint(context,mainThis,pointXY,flag) {
        // console.log([pointXY[0]*mainThis.width/mainThis.domain,pointXY[1]*mainThis.width/mainThis.domain])
        __addFunctionPoint(context,mainThis,[pointXY[0]*mainThis.width/mainThis.domain,pointXY[1]*mainThis.width/mainThis.range],flag)
    }
    dwar.addFunctionPoint = partial(_addFunctionPoint,context,mainThis)
    
	function _connectAllFunction(context,mainThis) {
        if (!mainThis.allFunctionPoint[0]) return;
        context.beginPath()
		for (i=0;i<mainThis.allFunctionPoint.length;i++) {
            if (mainThis.allFunctionPoint[i][0] != mainThis.x && mainThis.allFunctionPoint[i][1] != mainThis.y) {
                context.lineTo(mainThis.allFunctionPoint[i][0],mainThis.allFunctionPoint[i][1]);}
		}
		
		context.stroke();
        mainThis.allFunctionPoint = []
	}
    dwar.connectAllFunction = partial(_connectAllFunction,context,mainThis)
    
	function _connectAll(context,mainThis) {
        if (!mainThis.allPoint[0]) return;
        context.beginPath();
		for (i=0;i<mainThis.allPoint.length;i++) {
                context.lineTo(mainThis.allPoint[i][0],mainThis.allPoint[i][1]);
		}
		
		context.stroke();
        mainThis.allPoint = []
	}
	dwar.connectAll = partial(_connectAll,context,mainThis)
    
    function _addFunction(context,mainThis,f,domain) {
        min = domain[0];
        max = domain[1];
        weigth = max - min;
        
        y_list = []
        for (i=0;i<1000;i++)
        {
            var x = min+weigth/1000*i;
            y_list[i] = f(x);
        }

        for (j=0;j<y_list[0].length;j++) {
            for (i=0;i<y_list.length;i++) {
                var x = min+weigth/1000*i;
                _addFunctionPoint(context,mainThis,[x,y_list[i][j]])
            }
            _connectAllFunction(context,mainThis)
        }
    }
    dwar.addFunction = partial(_addFunction,context,mainThis)
    
    function _addText(context,mainThis,text,textXY) {
        context.fillText(text,mainThis.x+textXY[0],mainThis.y-textXY[1])
    }
    dwar.addText = partial(_addText,context,mainThis)
    
    // --------------------------------------------------------------------
    function f(x) {
        // f(x): 7x^2+9|x|y+5y^2 = 5
        if (x < 0) {
            a = 5
            b = 9 * x
            c = 7 * x * x - 5
            
            drt = window.Math.sqrt(b * b - 4 * a * c)
            return [(-b + drt) / (2 * a),(-b - drt) / (2 * a)]
        }
        else {
            a = 5
            b = - 9 * x
            c = 7 * x * x - 5
            drt = window.Math.sqrt(b * b - 4 * a * c)
            return [(-b + drt)/ (2 * a),(-b - drt)/ (2 * a)]
        }
    }
    function h(x) {
        // y = 2x^2 + 3x
        return [2 * x * x + 3 * x ]
    }
    function fa(x) {
        // y = log_3(x)
        return [window.Math.log(x)/window.Math.log(3)+0.5,]
    }
    function fb(x) {
        // y = sin(5x)
        return [window.Math.sin(5*x),]
    }
	dwar.init_coordinatemap([300,300],600);
    dwar.setGraduation(0)
    dwar.setBackground("#DDD")
    dwar.setScope(2,2);
	dwar.setColor("#999")
	dwar.addPositiveXaxis(context,mainThis)
	dwar.addPositiveYaxis(context,mainThis)
	dwar.addNegativeXaxis(context,mainThis)
	dwar.addNegativeYaxis(context,mainThis)
    dwar.setColor("#111")
    dwar.addPoint([1.5,1.5])
    dwar.addFunction(f,[-2,2])
    dwar.setColor("#D5F")
    dwar.addFunction(fa,[0.001,2])
    dwar.setColor("#3D5")
    dwar.addFunction(h,[-2,2])
    dwar.setColor("#678")
    dwar.addFunction(fb,[-2,2])
    dwar.addText("f(x): 7x^2+9|x|y+5y^2=5",[100,-210]) 
    dwar.addText("g(x): 2x^2 + 3x",[100,-230])
    dwar.addText("h(x): log_3(x)",[100,-170])     
    dwar.addText("u(x): sin(5x)",[100,-190]) 
    dwar.addPoint([0.5,0.2])
    dwar.addPoint([-0.5,0.3])
    dwar.connectAll()
</script>

<script>
    domain = window.mainThis.domain
    range = window.mainThis.range
    width = window.mainThis.width
    
    function cnvs_getCoordinates(e) {
        x = ((e.clientX - 300)*domain/width).toFixed(2);
        y = ((-e.clientY + 300)*range/width).toFixed(2);
        document.getElementById("xycoordinates").innerHTML="Coordinates: (" + x + "," + y + ")";
    }
     
    function cnvs_clearCoordinates() {
        document.getElementById("xycoordinates").innerHTML="";
    }
</script>
</html>